package com.nec.recommend.module.system.service.impl;

import com.nec.recommend.auth.AuthUser;
import com.nec.recommend.consts.CacheGroupConst;
import com.nec.recommend.consts.TokenConst;
import com.nec.recommend.exception.ServiceException;
import com.nec.recommend.module.system.dto.UserInfoDTO;
import com.nec.recommend.module.system.service.LoginService;
import com.nec.recommend.module.system.service.UserService;
import com.nec.recommend.module.system.vo.LoginUserVO;
import com.nec.recommend.module.system.vo.UpdatePwdVO;
import com.nec.recommend.utils.AuthUserUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    private final UserService userService;
    private final RedisTemplate<String, Object> redisTemplate;

    public LoginServiceImpl(UserService userService, RedisTemplate<String, Object> redisTemplate) {
        this.userService = userService;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public AuthUser login(LoginUserVO loginUser, HttpServletRequest request) {
        String client = request.getHeader("client");
        if (StringUtils.isBlank(client) || !TokenConst.clients.contains(client)) {
            client = TokenConst.WEAPP;
        }
        UserInfoDTO userInfoDTO = userService.queryByAccount(loginUser.getAccount());

        if (Objects.isNull(userInfoDTO) || (StringUtils.equals(client, TokenConst.MANAGE))) {
            throw new ServiceException("用户不存在！");
        }
        if (!AuthUserUtils.matchPwd(userInfoDTO.getPassword(), loginUser.getPassword(), loginUser.getAccount())) {
            throw new ServiceException("密码错误！");
        }
        String token = request.getHeader(TokenConst.TOKEN_HEADER);
        if (StringUtils.isNotEmpty(token)) {
            redisTemplate.delete(CacheGroupConst.MANAGE_USER_SESSION + token.replaceAll(TokenConst.TOKEN_PREFIX, ""));
        }
        AuthUser authUser = packAuthUser(userInfoDTO);
        redisTemplate.opsForValue().set(CacheGroupConst.MANAGE_USER_SESSION + authUser.getToken(), authUser, TokenConst.TOKEN_EXPIRE, TokenConst.EXPIRE_UNIT);
        return authUser;
    }

    @Override
    public AuthUser refreshToken(HttpServletRequest request) {
        //从请求头中获取token
        String token = request.getHeader(TokenConst.TOKEN_HEADER);
        if (Strings.isNotEmpty(token)) {
            String tokenKey = CacheGroupConst.MANAGE_USER_SESSION + token.replaceAll(TokenConst.TOKEN_PREFIX, "");
            //从redis中获取用户会话信息
            Object o = redisTemplate.opsForValue().get(tokenKey);
            if (Objects.nonNull(o)) {
                AuthUser authUser = (AuthUser) o;
                UserInfoDTO userInfoDTO = userService.queryByAccount(authUser.getPhone());
                redisTemplate.delete(tokenKey);
                if (Objects.isNull(userInfoDTO)) {
                    throw new ServiceException("用户不存在！");
                }
                authUser = packAuthUser(userInfoDTO);
                redisTemplate.opsForValue().set(CacheGroupConst.MANAGE_USER_SESSION + authUser.getToken(), authUser, 7, TimeUnit.DAYS);
                return authUser;
            }
        }
        throw new ServiceException("token无效，无法刷新会话！");
    }

    @Override
    public void logout(HttpServletRequest request) {
        String token = request.getHeader(TokenConst.TOKEN_HEADER);
        if (Strings.isNotEmpty(token)) {
            redisTemplate.delete(CacheGroupConst.MANAGE_USER_SESSION + token.replaceAll(TokenConst.TOKEN_PREFIX, ""));
        }
    }

    /**
     * 封装会话用户信息
     *
     * @param userInfoDTO 完整的用户信息
     * @return 会话用户
     */
    private AuthUser packAuthUser(UserInfoDTO userInfoDTO) {
        AuthUser authUser = new AuthUser();
        authUser.setPhone(userInfoDTO.getPhone());
        authUser.setAvatar(userInfoDTO.getAvatar());
        authUser.setName(userInfoDTO.getName());
        authUser.setSex(userInfoDTO.getSex());
        authUser.setCityCode(userInfoDTO.getCityCode());
        authUser.setCityName(userInfoDTO.getCityName());
        authUser.setProvinceCode(userInfoDTO.getProvinceCode());
        authUser.setProvinceName(userInfoDTO.getProvinceName());
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        authUser.setToken(token);
        return authUser;
    }

    @Override
    public Boolean updatePwd(UpdatePwdVO updatePwdVO, HttpServletRequest request) {
        String salt = AuthUserUtils.getUser().getPhone();
        boolean flag = userService.updatePwd(AuthUserUtils.getUser().getPhone(), AuthUserUtils.encodePwd(updatePwdVO.getOldPwd(), salt), AuthUserUtils.encodePwd(updatePwdVO.getNewPwd(), salt));
        if (flag) {
            logout(request);
            return true;
        }
        throw new ServiceException("旧密码错误");
    }
}
